home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / Libraries / DCLAP 6d / dclap6d / vibrant / viewer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-05  |  55.7 KB  |  1,851 lines  |  [TEXT/R*ch]

  1. /*   viewer.c
  2. * ===========================================================================
  3. *
  4. *                            PUBLIC DOMAIN NOTICE
  5. *            National Center for Biotechnology Information (NCBI)
  6. *
  7. *  This software/database is a "United States Government Work" under the
  8. *  terms of the United States Copyright Act.  It was written as part of
  9. *  the author's official duties as a United States Government employee and
  10. *  thus cannot be copyrighted.  This software/database is freely available
  11. *  to the public for use. The National Library of Medicine and the U.S.
  12. *  Government do not place any restriction on its use or reproduction.
  13. *  We would, however, appreciate having the NCBI and the author cited in
  14. *  any work or product based on this material
  15. *
  16. *  Although all reasonable efforts have been taken to ensure the accuracy
  17. *  and reliability of the software and data, the NLM and the U.S.
  18. *  Government do not and cannot warrant the performance or results that
  19. *  may be obtained by using this software or data. The NLM and the U.S.
  20. *  Government disclaim all warranties, express or implied, including
  21. *  warranties of performance, merchantability or fitness for any particular
  22. *  purpose.
  23. *
  24. * ===========================================================================
  25. *
  26. * File Name:  viewer.c
  27. *
  28. * Author:  Jonathan Kans, Jill Shermer
  29. *
  30. * Version Creation Date:   10/25/92
  31. *
  32. * $Revision: 1.36 $
  33. *
  34. * File Description: 
  35. *
  36. * Modifications:  
  37. * --------------------------------------------------------------------------
  38. * Date     Name        Description of modification
  39. * -------  ----------  -----------------------------------------------------
  40. *
  41. *
  42. * ==========================================================================
  43. */
  44.  
  45. #ifndef _VIBRANT_
  46. #include <vibrant.h>
  47. #endif
  48.  
  49. #ifndef _PICTURE_
  50. #include <picture.h>
  51. #endif
  52.  
  53. #ifndef _PICTUREP_
  54. #include <pictureP.h>
  55. #endif
  56.  
  57. #ifndef _MAPPINGP_
  58. #include <mappingP.h>
  59. #endif
  60.  
  61. #ifndef _DRAWINGP_
  62. #include <drawingP.h>
  63. #endif
  64.  
  65. #ifndef _VIEWER_
  66. #include <viewer.h>
  67. #endif
  68.  
  69. #ifndef _VIEWERP_
  70. #include <viewerP.h>
  71. #endif
  72.  
  73. /*****************************************************************************
  74. *
  75. *   INTERNAL TYPE DEFINES
  76. *
  77. *****************************************************************************/
  78.  
  79. #ifdef WIN_MOTIF
  80. #define LINE_PROXIMITY    12
  81. #define RECT_PROXIMITY     6
  82. #define GENERAL_PROXIMITY  6
  83. #else
  84. #define LINE_PROXIMITY     6
  85. #define RECT_PROXIMITY     3
  86. #define GENERAL_PROXIMITY  3
  87. #endif
  88.  
  89. /*****************************************************************************
  90. *
  91. *   ViewerVScrollProc (sb, viewer, newval, oldval)
  92. *
  93. *****************************************************************************/
  94.  
  95. static void ViewerVScrollProc (BaR sb, SlatE viewer, Int2 newval, Int2 oldval)
  96.  
  97. {
  98.   ViewPData  extra;
  99.   Int2       height;
  100.   Int4       lineHeight;
  101.   Int4       offsetY;
  102.   Int2       pixels;
  103.   RecT       r;
  104.   Int2       visLines;
  105.  
  106.   if (viewer != NULL && oldval != newval) {
  107.     if (Visible (viewer) && AllParentsVisible (viewer)) {
  108.       GetPanelExtra ((PaneL) viewer, &extra);
  109.       ObjectRect (viewer, &r);
  110.       InsetRect (&r, 4, 4);
  111.       height = r.bottom - r.top;
  112.       lineHeight = extra.scale.scaleY * (Int4) extra.scale.scrollY;
  113.       visLines = (height) / extra.scale.scrollY;
  114.       Select (viewer);
  115.       if ((newval > oldval && newval - visLines + 1 <= oldval) ||
  116.           (newval < oldval && newval + visLines - 1 >= oldval)) {
  117.         pixels = (newval - oldval) * extra.scale.scrollY;
  118.         if (ABS (pixels) < height) {
  119.           ScrollRect (&r, 0, -pixels);
  120.           if (pixels > 0) {
  121.             r.top = r.bottom - pixels;
  122.           } else {
  123.             r.bottom = r.top - pixels;
  124.           }
  125.           InsetRect (&r, -1, -1);
  126.           InvalRect (&r);
  127.         } else {
  128.           InsetRect (&r, -1, -1);
  129.           InvalRect (&r);
  130.         }
  131.       } else {
  132.         InsetRect (&r, -1, -1);
  133.         InvalRect (&r);
  134.       }
  135.       offsetY = lineHeight * (Int4) (newval - oldval);
  136.       extra.scale.port.top -= offsetY;
  137.       extra.scale.port.bottom -= offsetY;
  138.       SetPanelExtra ((PaneL) viewer, &extra);
  139.       Update ();
  140.       if (extra.pan != NULL) {
  141.         extra.pan ((VieweR) viewer, extra.picture);
  142.       }
  143.     }
  144.   }
  145. }
  146.  
  147. /*****************************************************************************
  148. *
  149. *   ViewerHScrollProc (sb, viewer, newval, oldval)
  150. *
  151. *****************************************************************************/
  152.  
  153. static void ViewerHScrollProc (BaR sb, SlatE viewer, Int2 newval, Int2 oldval)
  154.  
  155. {
  156.   ViewPData  extra;
  157.   Int4       lineWidth;
  158.   Int4       offsetX;
  159.   Int2       pixels;
  160.   RecT       r;
  161.   Int2       visLines;
  162.   Int2       width;
  163.  
  164.   if (viewer != NULL && oldval != newval) {
  165.     if (Visible (viewer) && AllParentsVisible (viewer)) {
  166.       GetPanelExtra ((PaneL) viewer, &extra);
  167.       ObjectRect (viewer, &r);
  168.       InsetRect (&r, 4, 4);
  169.       width = r.right - r.left;
  170.       lineWidth = extra.scale.scaleX * (Int4) extra.scale.scrollX;
  171.       visLines = (width) / extra.scale.scrollX;
  172.       Select (viewer);
  173.       if ((newval > oldval && newval - visLines + 1 <= oldval) ||
  174.           (newval < oldval && newval + visLines - 1 >= oldval)) {
  175.         pixels = (newval - oldval) * extra.scale.scrollX;
  176.         if (ABS (pixels) < width) {
  177.           ScrollRect (&r, -pixels, 0);
  178.           if (pixels > 0) {
  179.             r.left = r.right - pixels;
  180.           } else {
  181.             r.right = r.left - pixels;
  182.           }
  183.           InsetRect (&r, -1, -1);
  184.           InvalRect (&r);
  185.         } else {
  186.           InsetRect (&r, -1, -1);
  187.           InvalRect (&r);
  188.         }
  189.       } else {
  190.         InsetRect (&r, -1, -1);
  191.         InvalRect (&r);
  192.       }
  193.       offsetX = lineWidth * (Int4) (newval - oldval);
  194.       extra.scale.port.left += offsetX;
  195.       extra.scale.port.right += offsetX;
  196.       SetPanelExtra ((PaneL) viewer, &extra);
  197.       Update ();
  198.       if (extra.pan != NULL) {
  199.         extra.pan ((VieweR) viewer, extra.picture);
  200.       }
  201.     }
  202.   }
  203. }
  204.  
  205. /*****************************************************************************
  206. *
  207. *   SetAttributes (atts, current)
  208. *       Sets the drawing system to the specified attributes
  209. *
  210. *****************************************************************************/
  211.  
  212. static void SetAttributes (AttPData *atts, AttPData *current)
  213.  
  214. {
  215.   if (atts != NULL && current != NULL) {
  216.     if (atts->color [0] != current->color [0] ||
  217.         atts->color [1] != current->color [1] ||
  218.         atts->color [2] != current->color [2] ) {
  219.       SelectColor (atts->color [0], atts->color [1], atts->color [2]);
  220.       current->color [0] = atts->color [0];
  221.       current->color [1] = atts->color [1];
  222.       current->color [2] = atts->color [2];
  223.     }
  224.     if (atts->linestyle != current->linestyle) {
  225.       switch (atts->linestyle) {
  226.         case NO_LINE_STYLE :
  227.           break;
  228.         case SOLID_LINE :
  229.           Solid ();
  230.           break;
  231.         case DOTTED_LINE :
  232.           Dotted ();
  233.           break;
  234.         case DASHED_LINE :
  235.           Dashed ();
  236.           break;
  237.         default :
  238.           break;
  239.       }
  240.       current->linestyle = atts->linestyle;
  241.     }
  242.     if (atts->penwidth != current->penwidth) {
  243.       WidePen (atts->penwidth);
  244.       current->penwidth = atts->penwidth;
  245.     }
  246.     if (atts->shading != current->shading) {
  247.       switch (atts->shading) {
  248.         case NO_SHADING :
  249.           break;
  250.         case SOLID_SHADING :
  251.           Solid ();
  252.           break;
  253.         case DARK_SHADING :
  254.           Dark ();
  255.           break;
  256.         case MEDIUM_SHADING :
  257.           Medium ();
  258.           break;
  259.         case LIGHT_SHADING :
  260.           Light ();
  261.           break;
  262.         case EMPTY_SHADING :
  263.           Empty ();
  264.           break;
  265.         default :
  266.           break;
  267.       }
  268.       current->shading = atts->shading;
  269.     }
  270.     if (atts->mode != current->mode) {
  271.       switch (atts->mode) {
  272.         case NO_MODE :
  273.           break;
  274.         case COPY_MODE :
  275.           CopyMode ();
  276.           break;
  277.         case MERGE_MODE :
  278.           MergeMode ();
  279.           break;
  280.         case INVERT_MODE :
  281.           InvertMode ();
  282.           break;
  283.         case ERASE_MODE :
  284.           EraseMode ();
  285.           break;
  286.         default :
  287.           break;
  288.       }
  289.       current->mode = atts->mode;
  290.     }
  291.     if (atts->highlight != current->highlight) {
  292.       current->highlight = atts->highlight;
  293.     }
  294.   }
  295. }
  296.  
  297. /*****************************************************************************
  298. *
  299. *   SegmentAndParentsVisible (seg)
  300. *       Returns true if segment and all parent segments are visible
  301. *
  302. *****************************************************************************/
  303.  
  304. static Boolean SegmentAndParentsVisible (SegPPtr seg)
  305.  
  306. {
  307.   Boolean  vis;
  308.  
  309.   vis = TRUE;
  310.   while (seg != NULL && vis) {
  311.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  312.       vis =  seg->seg.visible;
  313.     } else {
  314.       Message (MSG_ERROR, "SegmentAndParentsVisible argument not a segment or picture");
  315.     }
  316.     seg = (SegPPtr) seg->seg.parent;
  317.   }
  318.   return vis;
  319. }
  320.  
  321. /*****************************************************************************
  322. *
  323. *   DrawSegment (seg, atts, current, scale)
  324. *       Draws a segment, recursively tracking attributes
  325. *
  326. *****************************************************************************/
  327.  
  328. static void DrawSegment (SegPPtr seg, AttPData *atts, AttPData *current, ScaleInfo *scale)
  329.  
  330. {
  331.   AttPPtr   att;
  332.   AttPData  attributes;
  333.   BasePPtr  item;
  334.   RecT      r;
  335.  
  336.   if (seg != NULL && atts != NULL && current != NULL && scale != NULL) {
  337.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  338.       if (seg->seg.maxscale == 0 || seg->seg.maxscale >= MAX (scale->scaleX, scale->scaleY)) {
  339.       if (BoxInViewport (&r, &(seg->seg.box), &(seg->seg.margin), scale)) {
  340.           attributes = *(atts);
  341.           if (seg->seg.highlight != PLAIN_SEGMENT) {
  342.             attributes.highlight = seg->seg.highlight;
  343.           }
  344.           SetAttributes (&attributes, current);
  345.           if (seg->seg.visible && SegmentAndParentsVisible (seg)) {
  346.             item = seg->seg.head;
  347.             while (item != NULL) {
  348.               switch (item->code) {
  349.                 case UNKNOWN :
  350.                   Message (MSG_ERROR, "DrawSegment child is unknown");
  351.                   break;
  352.                 case PICTURE :
  353.                   Message (MSG_ERROR, "DrawSegment child is a picture");
  354.                   break;
  355.                 case SEGMENT :
  356.                   DrawSegment ((SegPPtr) item, &attributes, current, scale);
  357.                   SetAttributes (&attributes, current);
  358.                   break;
  359.                 case ATTRIBUTE :
  360.                   att = (AttPPtr) item;
  361.                   attributes.flags = att->att.flags;
  362.                   if (attributes.flags & COLOR_ATT) {
  363.                     attributes.color [0] = att->att.color [0];
  364.                     attributes.color [1] = att->att.color [1];
  365.                     attributes.color [2] = att->att.color [2];
  366.                   }
  367.                   if (attributes.flags & STYLE_ATT) {
  368.                     attributes.linestyle = att->att.linestyle;
  369.                   }
  370.                   if (attributes.flags & SHADING_ATT) {
  371.                     attributes.shading = att->att.shading;
  372.                   }
  373.                   if (attributes.flags & WIDTH_ATT) {
  374.                     attributes.penwidth = att->att.penwidth;
  375.                   }
  376.                   if (attributes.flags & MODE_ATT) {
  377.                     attributes.mode = att->att.mode;
  378.                   }
  379.                   SetAttributes (&attributes, current);
  380.                   break;
  381.                 default :
  382.                   DrawPrimitive (item, &attributes, scale);
  383.                   break;
  384.               }
  385.               item = item->next;
  386.             }
  387.             InsetRect (&r, -1, -1);
  388.             if (scale->force || RectInRgn (&r, updateRgn)) {
  389.               switch (seg->seg.highlight) {
  390.                 case PLAIN_SEGMENT :
  391.                   break;
  392.                 case FRAME_SEGMENT :
  393.                   FrameRect (&r);
  394.                   break;
  395.                 case FILL_SEGMENT :
  396.                   PaintRect (&r);
  397.                   break;
  398.                 default :
  399.                   break;
  400.               }
  401.             }
  402.           }
  403.         }
  404.       }
  405.     } else {
  406.       Message (MSG_ERROR, "DrawSegment argument not a segment or picture");
  407.     }
  408.   }
  409. }
  410.  
  411. /*****************************************************************************
  412. *
  413. *   DrawViewerProc (viewer)
  414. *       Draws the picture in a viewer panel.  Clipping is to the intersection
  415. *       of the updateRgn (the portion of the panel exposed) and the inset area
  416. *       of the viewer, leaving a four-pixel margin.
  417. *
  418. *****************************************************************************/
  419.  
  420. static void DrawViewerProc (PaneL viewer)
  421.  
  422. {
  423.   AttPData   attributes;
  424.   AttPData   current;
  425.   RegioN     dst;
  426.   ViewPData  extra;
  427.   PicPPtr    pic;
  428.   RegioN     src;
  429.  
  430.   if (viewer != NULL) {
  431.     GetPanelExtra (viewer, &extra);
  432.     pic = (PicPPtr) extra.picture;
  433.     if (pic != NULL) {
  434.       if (pic->base.code == PICTURE) {
  435.         src = CreateRgn ();
  436.         dst = CreateRgn ();
  437.         LoadRectRgn (src, extra.scale.view.left, extra.scale.view.top,
  438.                      extra.scale.view.right, extra.scale.view.bottom);
  439.         SectRgn (src, updateRgn, dst);
  440.         ClipRgn (dst);
  441.         DestroyRgn (src);
  442.         DestroyRgn (dst);
  443.         attributes.flags = NO_ATTS;
  444.         attributes.color [0] = BLACK_COLOR [0];
  445.         attributes.color [1] = BLACK_COLOR [1];
  446.         attributes.color [2] = BLACK_COLOR [2];
  447.         attributes.linestyle = SOLID_LINE;
  448.         attributes.shading = SOLID_SHADING;
  449.         attributes.penwidth = STD_PEN_WIDTH;
  450.         attributes.mode = COPY_MODE;
  451.         attributes.highlight = PLAIN_SEGMENT;
  452.         current = *(&attributes);
  453.         DrawSegment ((SegPPtr) pic, &attributes, ¤t, &(extra.scale));
  454.         SetAttributes (&attributes, ¤t);
  455.         if (extra.draw != NULL) {
  456.           extra.draw ((VieweR) viewer, extra.picture);
  457.         }
  458.         ResetClip ();
  459.       } else {
  460.         Message (MSG_ERROR, "DrawViewerProc target is not a picture");
  461.       }
  462.     }
  463.   }
  464. }
  465.  
  466. /*****************************************************************************
  467. *
  468. *   ViewerClickProc (viewer, pt)
  469. *
  470. *****************************************************************************/
  471.  
  472. static void ViewerClickProc (PaneL viewer, PoinT pt)
  473.  
  474. {
  475.   ViewPData  extra;
  476.  
  477.   GetPanelExtra (viewer, &extra);
  478.   if (extra.click != NULL && extra.picture != NULL) {
  479.     extra.click ((VieweR) viewer, extra.picture, pt);
  480.   }
  481. }
  482.  
  483. /*****************************************************************************
  484. *
  485. *   ViewerDragProc (viewer, pt)
  486. *
  487. *****************************************************************************/
  488.  
  489. static void ViewerDragProc (PaneL viewer, PoinT pt)
  490.  
  491. {
  492.   ViewPData  extra;
  493.  
  494.   GetPanelExtra (viewer, &extra);
  495.   if (extra.drag != NULL && extra.picture != NULL) {
  496.     extra.drag ((VieweR) viewer, extra.picture, pt);
  497.   }
  498. }
  499.  
  500. /*****************************************************************************
  501. *
  502. *   ViewerReleaseProc (viewer, pt)
  503. *
  504. *****************************************************************************/
  505.  
  506. static void ViewerReleaseProc (PaneL viewer, PoinT pt)
  507.  
  508. {
  509.   ViewPData  extra;
  510.  
  511.   GetPanelExtra (viewer, &extra);
  512.   if (extra.release != NULL && extra.picture != NULL) {
  513.     extra.release ((VieweR) viewer, extra.picture, pt);
  514.   }
  515. }
  516.  
  517. /*****************************************************************************
  518. *
  519. *   ResetViewerProc (viewer)
  520. *       Clears the panel extra data to remove references to the picture,
  521. *       and calls the cleanup procedure to free any attached instance data
  522. *
  523. *****************************************************************************/
  524.  
  525. static void ResetViewerProc (PaneL viewer)
  526.  
  527. {
  528.   ViewPData  extra;
  529.  
  530.   GetPanelExtra (viewer, &extra);
  531.   if (extra.data != NULL && extra.cleanup != NULL) {
  532.     extra.cleanup ((VieweR) viewer, extra.data);
  533.   }
  534.   extra.draw = NULL;
  535.   extra.data = NULL;
  536.   extra.cleanup = NULL;
  537.   MemSet ((VoidPtr) (&extra), 0, sizeof (ViewPData));
  538.   SetPanelExtra (viewer, &extra);
  539. }
  540.  
  541. /*****************************************************************************
  542. *
  543. *   CreateViewer (prnt, width, height, vscoll, hscroll)
  544. *       Creates a viewer panel
  545. *
  546. *****************************************************************************/
  547.  
  548. VieweR CreateViewer (GrouP prnt, Int2 width, Int2 height, Boolean vscroll, Boolean hscroll)
  549.  
  550. {
  551.   ViewPData    extra;
  552.   SltScrlProc  hscrproc;
  553.   Int2         margin;
  554.   PaneL        viewer;
  555.   SltScrlProc  vscrproc;
  556.  
  557.   viewer = NULL;
  558.   if (prnt != NULL) {
  559.     margin = 8;
  560.     if (vscroll) {
  561.       vscrproc = ViewerVScrollProc;
  562.       margin = 0;
  563.     } else {
  564.       vscrproc = NULL;
  565.     }
  566.     if (hscroll) {
  567.       hscrproc = ViewerHScrollProc;
  568.       margin = 0;
  569.     } else {
  570.       hscrproc = NULL;
  571.     }
  572.     viewer = AutonomousPanel (prnt, width + margin, height + margin,
  573.                               DrawViewerProc, vscrproc, hscrproc,
  574.                               sizeof (ViewPData), ResetViewerProc, NULL);
  575.     if (viewer != NULL) {
  576.       SetPanelClick (viewer, ViewerClickProc, ViewerDragProc, NULL, ViewerReleaseProc);
  577.       MemSet ((VoidPtr) (&extra), 0, sizeof (ViewPData));
  578.       extra.picture = NULL;
  579.       SetPanelExtra (viewer, &extra);
  580.     }
  581.   }
  582.   return (VieweR) viewer;
  583. }
  584.  
  585. /*****************************************************************************
  586. *
  587. *   ResetViewer (viewer)
  588. *       Resets a viewer panel
  589. *
  590. *****************************************************************************/
  591.  
  592. void ResetViewer (VieweR viewer)
  593.  
  594. {
  595.   if (viewer != NULL) {
  596.     Reset (viewer);
  597.   }
  598. }
  599.  
  600. /*****************************************************************************
  601. *
  602. *   DeleteViewer (viewer)
  603. *       Removes a viewer panel
  604. *
  605. *****************************************************************************/
  606.  
  607. VieweR DeleteViewer (VieweR viewer)
  608.  
  609. {
  610.   if (viewer != NULL) {
  611.     viewer = (VieweR)Remove (viewer);
  612.   }
  613.   return viewer;
  614. }
  615.  
  616. /*****************************************************************************
  617. *
  618. *   PadUp (val, scale)
  619. *       Rounds a value up to be an even multiple of the scale factor
  620. *
  621. *****************************************************************************/
  622.  
  623. static Int4 PadUp (Int4 val, Int4 scale)
  624.  
  625. {
  626.   Int4  mod;
  627.  
  628.   if (val >= 0) {
  629.     mod = val % scale;
  630.     if (mod == 0) {
  631.       return val;
  632.     } else {
  633.       return val + scale - mod;
  634.     }
  635.   } else {
  636.     mod = (-val) % scale;
  637.     if (mod == 0) {
  638.       return val;
  639.     } else {
  640.       return val + scale - mod;
  641.     }
  642.   }
  643. }
  644.  
  645. /*****************************************************************************
  646. *
  647. *   PadDn (val, scale)
  648. *       Rounds a value down to be an even multiple of the scale factor
  649. *
  650. *****************************************************************************/
  651.  
  652. static Int4 PadDn (Int4 val, Int4 scale)
  653.  
  654. {
  655.   Int4  mod;
  656.  
  657.   if (val >= 0) {
  658.     mod = val % scale;
  659.     if (mod == 0) {
  660.       return val;
  661.     } else {
  662.       return val - mod;
  663.     }
  664.   } else {
  665.     mod = (-val) % scale;
  666.     if (mod == 0) {
  667.       return val;
  668.     } else {
  669.       return val - scale + mod;
  670.     }
  671.   }
  672. }
  673.  
  674. /*****************************************************************************
  675. *
  676. *   PadBox (box, scaleX, scaleY)
  677. *       Expands a box boundaries to all be even multiples of scale factors
  678. *
  679. *****************************************************************************/
  680.  
  681. static void PadBox (BoxPtr box, Int4 scaleX, Int4 scaleY)
  682.  
  683. {
  684.   if (box != NULL && scaleX > 0 && scaleY > 0) {
  685.     box->left = PadDn (box->left, scaleX);
  686.     box->top = PadUp (box->top, scaleY);
  687.     box->right = PadUp (box->right, scaleX);
  688.     box->bottom = PadDn (box->bottom, scaleY);
  689.   }
  690. }
  691.  
  692. /*****************************************************************************
  693. *
  694. *   NormalizeBox (box)
  695. *       Ensures that left <= right and bottom <= top in world coordinates
  696. *
  697. *****************************************************************************/
  698.  
  699. static void NormalizeBox (BoxPtr box)
  700.  
  701. {
  702.   Int4  swap;
  703.  
  704.   if (box != NULL) {
  705.     if (box->left > box->right) {
  706.       swap = box->left;
  707.       box->left = box->right;
  708.       box->right = swap;
  709.     }
  710.     if (box->bottom > box->top) {
  711.       swap = box->bottom;
  712.       box->bottom = box->top;
  713.       box->top = swap;
  714.     }
  715.   }
  716. }
  717.  
  718. /*****************************************************************************
  719. *
  720. *   CalculateScaling (viewer, picture, pntX, pntY, align,
  721. *                     scaleX, scaleY, scalePtr, linHgtPtr,
  722. *                     linWidPtr, scrolXPtr, scrolYPtr)
  723. *       Performs scaling calculations in attaching a picture to a viewer
  724. *
  725. *****************************************************************************/
  726.  
  727. static void CalculateScaling (VieweR viewer, SegmenT picture, Int4 pntX, Int4 pntY,
  728.                               Int2 align, Int4 scaleX, Int4 scaleY, ScalePtr scalePtr,
  729.                               Int4Ptr linHgtPtr, Int4Ptr linWidPtr,
  730.                               Int2Ptr scrolXPtr, Int2Ptr scrolYPtr)
  731.  
  732. {
  733.   Int4       delta;
  734.   Int4       height;
  735.   Int4       lineHeight;
  736.   Int4       lineWidth;
  737.   Boolean    maxXscale;
  738.   Boolean    maxYscale;
  739.   Int4       originalX;
  740.   Int4       originalY;
  741.   PicPPtr    pic;
  742.   BoxInfo    port;
  743.   Int2       scrollX;
  744.   Int2       scrollY;
  745.   RecT       view;
  746.   Int4       width;
  747.   BoxInfo    world;
  748.   Int4       zoomX;
  749.   Int4       zoomY;
  750.  
  751.   if (viewer != NULL && picture != NULL && scalePtr != NULL) {
  752.     SelectFont (systemFont);
  753.     pic = (PicPPtr) picture;
  754.     if (pic->base.code == PICTURE) {
  755.  
  756.       world.left = pic->seg.box.left;
  757.       world.top = pic->seg.box.top + 1;
  758.       world.right = pic->seg.box.right + 1;
  759.       world.bottom = pic->seg.box.bottom;
  760.       NormalizeBox (&world);
  761.  
  762.       ObjectRect (viewer, &view);
  763.       InsetRect (&view, 4, 4);
  764.  
  765.       maxXscale = (Boolean) (scaleX == 0);
  766.       maxYscale = (Boolean) (scaleY == 0);
  767.       if (maxXscale) {
  768.         scaleX = (world.right - world.left + 1) / (Int4) (view.right - view.left) + 1;
  769.       } else {
  770.         scaleX = MAX (scaleX, 1);
  771.       }
  772.       if (maxYscale) {
  773.         scaleY = (world.top - world.bottom + 1) / (Int4) (view.bottom - view.top) + 1;
  774.       } else {
  775.         scaleY = MAX (scaleY, 1);
  776.       }
  777.       scrollX = 10;
  778.       scrollY = 10;
  779.  
  780.       zoomX = MIN (scaleX, (world.right - world.left + 1) /
  781.                    (Int4) (view.right - view.left) + 1);
  782.       zoomY = MIN (scaleY, (world.top - world.bottom + 1) /
  783.                    (Int4) (view.bottom - view.top) + 1);
  784.       lineWidth = zoomX * (Int4) scrollX;
  785.       lineHeight = zoomY * (Int4) scrollY;
  786.  
  787.       world.left -= zoomX - (Int4) pic->seg.margin.left * zoomX;
  788.       world.top += zoomY - (Int4) pic->seg.margin.top * zoomY;
  789.       world.right += zoomX + (Int4) pic->seg.margin.right * zoomX;
  790.       world.bottom -= zoomY + (Int4) pic->seg.margin.bottom * zoomY;
  791.       PadBox (&world, lineWidth, lineHeight);
  792.  
  793.       if (maxXscale) {
  794.         scaleX = (world.right - world.left + 1) / (Int4) (view.right - view.left) + 1;
  795.       } else {
  796.         scaleX = MIN (scaleX, (world.right - world.left + 1) /
  797.                       (Int4) (view.right - view.left) + 1);
  798.       }
  799.       if (maxYscale) {
  800.         scaleY = (world.top - world.bottom + 1) / (Int4) (view.bottom - view.top) + 1;
  801.       } else {
  802.         scaleY = MIN (scaleY, (world.top - world.bottom + 1) /
  803.                       (Int4) (view.bottom - view.top) + 1);
  804.       }
  805.       if (zoomX < scaleX || zoomY < scaleY) {
  806.         zoomX = scaleX;
  807.         zoomY = scaleY;
  808.         lineWidth = zoomX * (Int4) scrollX;
  809.         lineHeight = zoomY * (Int4) scrollY;
  810.         world.left = pic->seg.box.left - (zoomX - (Int4) pic->seg.margin.left * zoomX);
  811.         world.top = pic->seg.box.top + 1 + (zoomY - (Int4) pic->seg.margin.top * zoomY);
  812.         world.right = pic->seg.box.right + 1 + (zoomX + (Int4) pic->seg.margin.right * zoomX);
  813.         world.bottom = pic->seg.box.bottom - (zoomY + (Int4) pic->seg.margin.bottom * zoomY);
  814.         NormalizeBox (&world);
  815.         PadBox (&world, lineWidth, lineHeight);
  816.       }
  817.  
  818.       originalX = pntX;
  819.       originalY = pntY;
  820.       pntX = MAX (pntX, world.left);
  821.       pntX = MIN (pntX, world.right);
  822.       pntY = MAX (pntX, world.bottom);
  823.       pntY = MIN (pntY, world.top);
  824.       width = (Int4) (view.right - view.left) * scaleX;
  825.       height = (Int4) (view.bottom - view.top) * scaleY;
  826.       switch (align) {
  827.         case MIDDLE_CENTER :
  828.           pntX = (pntX / lineWidth) * lineWidth;
  829.           pntY = (pntY / lineHeight) * lineHeight;
  830.           port.left = pntX - (width / 2);
  831.           port.top = pntY + (height / 2);
  832.           port.right = pntX + (width / 2);
  833.           port.bottom = pntY - (height / 2);
  834.           break;
  835.         case UPPER_LEFT :
  836.           pntX = PadDn (pntX, lineWidth);
  837.           pntY = PadUp (pntY, lineHeight);
  838.           port.left = pntX;
  839.           port.top = pntY;
  840.           port.right = pntX + width;
  841.           port.bottom = pntY - height;
  842.           break;
  843.         case LOWER_LEFT :
  844.           pntX = PadDn (pntX, lineWidth);
  845.           pntY = PadDn (pntY, lineHeight);
  846.           port.left = pntX;
  847.           port.bottom = pntY;
  848.           port.right = pntX + width;
  849.           port.top = pntY + height;
  850.           break;
  851.         case UPPER_RIGHT :
  852.           pntX = PadUp (pntX, lineWidth);
  853.           pntY = PadUp (pntY, lineHeight);
  854.           port.right = pntX;
  855.           port.top = pntY;
  856.           port.left = pntX - width;
  857.           port.bottom = pntY - height;
  858.           break;
  859.         case LOWER_RIGHT :
  860.           pntX = PadUp (pntX, lineWidth);
  861.           pntY = PadDn (pntY, lineHeight);
  862.           port.right = pntX;
  863.           port.bottom = pntY;
  864.           port.left = pntX - width;
  865.           port.top = pntY + height;
  866.           break;
  867.         case UPPER_CENTER :
  868.           pntX = (pntX / lineWidth) * lineWidth;
  869.           pntY = PadUp (pntY, lineHeight);
  870.           port.left = pntX - (width / 2);
  871.           port.top = pntY;
  872.           port.right = pntX + (width / 2);
  873.           port.bottom = pntY - height;
  874.           break;
  875.         case LOWER_CENTER :
  876.           pntX = (pntX / lineWidth) * lineWidth;
  877.           pntY = PadDn (pntY, lineHeight);
  878.           port.left = pntX - (width / 2);
  879.           port.bottom = pntY;
  880.           port.right = pntX + (width / 2);
  881.           port.top = pntY + height;
  882.           break;
  883.         case MIDDLE_LEFT :
  884.           pntX = PadDn (pntX, lineWidth);
  885.           pntY = (pntY / lineHeight) * lineHeight;
  886.           port.left = pntX;
  887.           port.top = pntY + (height / 2);
  888.           port.right = pntX + width;
  889.           port.bottom = pntY - (height / 2);
  890.           break;
  891.         case MIDDLE_RIGHT :
  892.           pntX = PadUp (pntX, lineWidth);
  893.           pntY = (pntY / lineHeight) * lineHeight;
  894.           port.right = pntX;
  895.           port.top = pntY + (height / 2);
  896.           port.left = pntX - width;
  897.           port.bottom = pntY - (height / 2);
  898.           break;
  899.         default :
  900.           Message (MSG_ERROR, "AttachPicture align parameter is invalid");
  901.           break;
  902.       }
  903.       NormalizeBox (&port);
  904.  
  905.       if (port.right > world.right) {
  906.         delta = port.right - world.right;
  907.         port.left -= delta;
  908.         port.right -= delta;
  909.       }
  910.       if (port.left < world.left) {
  911.         delta = world.left - port.left;
  912.         port.left += delta;
  913.         port.right += delta;
  914.       }
  915.       if (port.bottom < world.bottom) {
  916.         delta = world.bottom - port.bottom;
  917.         port.top += delta;
  918.         port.bottom += delta;
  919.       }
  920.       if (port.top > world.top) {
  921.         delta = port.top - world.top;
  922.         port.top -= delta;
  923.         port.bottom -= delta;
  924.       }
  925.  
  926.       PadBox (&port, lineWidth, lineHeight);
  927.  
  928.       port.left = MAX (port.left, world.left);
  929.       port.top = MIN (port.top, world.top);
  930.       port.right = MIN (port.right, world.right);
  931.       port.bottom = MAX (port.bottom, world.bottom);
  932.  
  933.       if (port.left == world.left && port.right == world.right) {
  934.         switch (align) {
  935.           case UPPER_LEFT :
  936.           case MIDDLE_LEFT :
  937.           case LOWER_LEFT :
  938.             break;
  939.           case UPPER_CENTER :
  940.           case MIDDLE_CENTER :
  941.           case LOWER_CENTER :
  942.             delta = width - (port.right - port.left);
  943.             port.left -= delta / 2;
  944.             break;
  945.           case UPPER_RIGHT :
  946.           case MIDDLE_RIGHT :
  947.           case LOWER_RIGHT :
  948.             delta = width - (port.right - port.left);
  949.             port.left -= delta;
  950.             break;
  951.           default :
  952.             break;
  953.         }
  954.       } else if (originalX == INT4_MIN || originalX == INT4_MAX) {
  955.         switch (align) {
  956.           case UPPER_LEFT :
  957.           case MIDDLE_LEFT :
  958.           case LOWER_LEFT :
  959.             if (port.left > world.left) {
  960.               delta = port.left - world.left;
  961.               port.left -= delta;
  962.               port.right -= delta;
  963.             }
  964.             break;
  965.           case UPPER_CENTER :
  966.           case MIDDLE_CENTER :
  967.           case LOWER_CENTER :
  968.             break;
  969.           case UPPER_RIGHT :
  970.           case MIDDLE_RIGHT :
  971.           case LOWER_RIGHT :
  972.             if (port.right < world.right) {
  973.               delta = world.right - port.right;
  974.               port.left += delta;
  975.               port.right += delta;
  976.             }
  977.             break;
  978.           default :
  979.             break;
  980.         }
  981.       }
  982.  
  983.       if (port.top == world.top && port.bottom == world.bottom) {
  984.         switch (align) {
  985.           case UPPER_LEFT :
  986.           case UPPER_CENTER :
  987.           case UPPER_RIGHT :
  988.             delta = height - (port.top - port.bottom);
  989.             port.bottom -= delta;
  990.             break;
  991.           case MIDDLE_LEFT :
  992.           case MIDDLE_CENTER :
  993.           case MIDDLE_RIGHT :
  994.             delta = height - (port.top - port.bottom);
  995.             port.bottom -= delta / 2;
  996.             break;
  997.           case LOWER_LEFT :
  998.           case LOWER_CENTER :
  999.           case LOWER_RIGHT :
  1000.             break;
  1001.           default :
  1002.             break;
  1003.         }
  1004.       } else if (originalY == INT4_MIN || originalY == INT4_MAX) {
  1005.         switch (align) {
  1006.           case UPPER_LEFT :
  1007.           case UPPER_CENTER :
  1008.           case UPPER_RIGHT :
  1009.             if (port.top < world.top) {
  1010.               delta = world.top - port.top;
  1011.               port.top += delta;
  1012.               port.bottom += delta;
  1013.             }
  1014.             break;
  1015.           case MIDDLE_LEFT :
  1016.           case MIDDLE_CENTER :
  1017.           case MIDDLE_RIGHT :
  1018.             break;
  1019.           case LOWER_LEFT :
  1020.           case LOWER_CENTER :
  1021.           case LOWER_RIGHT :
  1022.             if (port.bottom > world.bottom) {
  1023.               delta = port.bottom - world.bottom;
  1024.               port.top -= delta;
  1025.               port.bottom -= delta;
  1026.             }
  1027.             break;
  1028.           default :
  1029.             break;
  1030.         }
  1031.       }
  1032.  
  1033.       scalePtr->world = world;
  1034.       scalePtr->view = view;
  1035.       scalePtr->port = port;
  1036.       scalePtr->scaleX = scaleX;
  1037.       scalePtr->scaleY = scaleY;
  1038.       scalePtr->scrollX = scrollX;
  1039.       scalePtr->scrollY = scrollY;
  1040.       scalePtr->force = FALSE;
  1041.  
  1042.       if (linHgtPtr != NULL) {
  1043.         *linHgtPtr = lineHeight;
  1044.       }
  1045.       if (linWidPtr != NULL) {
  1046.         *linWidPtr = lineWidth;
  1047.       }
  1048.       if (scrolXPtr != NULL) {
  1049.         *scrolXPtr = scrollX;
  1050.       }
  1051.       if (scrolYPtr != NULL) {
  1052.         *scrolYPtr = scrollY;
  1053.       }
  1054.  
  1055.     }
  1056.   }
  1057. }
  1058.  
  1059. /*****************************************************************************
  1060. *
  1061. *   EstimateScaling (viewer, picture, pntX, pntY, align, scaleX, scaleY)
  1062. *       Calculates maximum scaling factors in attaching a picture to a viewer
  1063. *
  1064. *****************************************************************************/
  1065.  
  1066. void EstimateScaling (VieweR viewer, SegmenT picture, Int4 pntX, Int4 pntY,
  1067.                       Int2 align, Int4Ptr scaleX, Int4Ptr scaleY)
  1068.  
  1069. {
  1070.   ScaleInfo  scale;
  1071.   PicPPtr    pic;
  1072.  
  1073.   if (viewer != NULL && picture != NULL) {
  1074.     SelectFont (systemFont);
  1075.     pic = (PicPPtr) picture;
  1076.     if (pic->base.code == PICTURE) {
  1077.       CalculateScaling (viewer, picture, pntX, pntY, align,
  1078.                         0, 0, &scale, NULL, NULL, NULL, NULL);
  1079.       if (scaleX != NULL) {
  1080.         *scaleX = scale.scaleX;
  1081.       }
  1082.       if (scaleY != NULL) {
  1083.         *scaleY = scale.scaleY;
  1084.       }
  1085.     }
  1086.   }
  1087. }
  1088.  
  1089. /*****************************************************************************
  1090. *
  1091. *   AttachCommon (viewer, picture, pntX, pntY, align,
  1092. *                 scaleX, scaleY, draw, data, cleanup)
  1093. *       Connects a picture to a viewer, mapping world coordinate boundaries
  1094. *       onto viewer panel, calculating scaling and offset factors.  If the
  1095. *       scaleX or scaleY parameters are 0, the minimum scale for which no
  1096. *       scrolling is necessary is used.  Extra instance data can be attached
  1097. *
  1098. *****************************************************************************/
  1099.  
  1100. static void AttachCommon (VieweR viewer, SegmenT picture, Int4 pntX, Int4 pntY,
  1101.                           Int2 align, Int4 scaleX, Int4 scaleY, VwrDrawProc draw,
  1102.                           VoidPtr data, VwrFreeProc cleanup)
  1103.  
  1104. {
  1105.   ViewPData  extra;
  1106.   Int4       lineHeight;
  1107.   Int4       lineWidth;
  1108.   Int4       numLines;
  1109.   PicPPtr    pic;
  1110.   BaR        sb;
  1111.   Int2       scrollX;
  1112.   Int2       scrollY;
  1113.   WindoW     tempPort;
  1114.   Int4       visLines;
  1115.  
  1116.   if (viewer != NULL && picture != NULL) {
  1117.     SelectFont (systemFont);
  1118.     pic = (PicPPtr) picture;
  1119.     if (pic->base.code == PICTURE) {
  1120.  
  1121.       extra.viewer = viewer;
  1122.       extra.picture = picture;
  1123.  
  1124.       CalculateScaling (viewer, picture, pntX, pntY, align, scaleX, scaleY,
  1125.                         &(extra.scale), &lineHeight, &lineWidth, &scrollX, &scrollY);
  1126.  
  1127.       extra.click = NULL;
  1128.       extra.drag = NULL;
  1129.       extra.release = NULL;
  1130.       extra.pan = NULL;
  1131.       extra.draw = draw;
  1132.  
  1133.       extra.data = data;
  1134.       extra.cleanup = cleanup;
  1135.       SetPanelExtra ((PaneL) viewer, &extra);
  1136.  
  1137.       sb = GetSlateHScrollBar ((SlatE) viewer);
  1138.       if (sb != NULL) {
  1139.         Reset (sb);
  1140.         numLines = (extra.scale.world.right - extra.scale.world.left) / lineWidth;
  1141.         visLines = (extra.scale.view.right - extra.scale.view.left) / (Int4) scrollX;
  1142.         if (visLines > 0 && numLines >= visLines) {
  1143.           SetRange (sb, (Int2) (visLines - 1), (Int2) (visLines - 1),
  1144.                     (Int2) (numLines - visLines));
  1145.           CorrectBarValue (sb, (Int2) ((extra.scale.port.left -
  1146.                            extra.scale.world.left) / lineWidth));
  1147.         }
  1148.       }
  1149.  
  1150.       sb = GetSlateVScrollBar ((SlatE) viewer);
  1151.       if (sb != NULL) {
  1152.         Reset (sb);
  1153.         numLines = (extra.scale.world.top - extra.scale.world.bottom) / lineHeight;
  1154.         visLines = (extra.scale.view.bottom - extra.scale.view.top) / (Int4) scrollY;
  1155.         if (visLines > 0 && numLines >= visLines) {
  1156.           SetRange (sb, (Int2) (visLines - 1), (Int2) (visLines - 1),
  1157.                     (Int2) (numLines - visLines));
  1158.           CorrectBarValue (sb, (Int2) ((extra.scale.world.top -
  1159.                            extra.scale.port.top) / lineHeight));
  1160.         }
  1161.       }
  1162.  
  1163.       if (Visible (viewer) && AllParentsVisible (viewer)) {
  1164.         tempPort = SavePort (viewer);
  1165.         Select (viewer);
  1166.         InvalRect (&(extra.scale.view));
  1167.         RestorePort (tempPort);
  1168.       }
  1169.     } else if (viewer != NULL) {
  1170.       Reset (viewer);
  1171.     } else {
  1172.       Message (MSG_ERROR, "AttachPicture argument not a picture");
  1173.     }
  1174.   }
  1175. }
  1176.  
  1177. /*****************************************************************************
  1178. *
  1179. *   AttachPicture (viewer, picture, pntX, pntY, align, scaleX, scaleY, draw)
  1180. *       Connects a picture to a viewer
  1181. *
  1182. *****************************************************************************/
  1183.  
  1184. void AttachPicture (VieweR viewer, SegmenT picture, Int4 pntX, Int4 pntY,
  1185.                     Int2 align, Int4 scaleX, Int4 scaleY, VwrDrawProc draw)
  1186.  
  1187. {
  1188.   AttachCommon (viewer, picture, pntX, pntY, align,
  1189.                 scaleX, scaleY, draw, NULL, NULL);
  1190. }
  1191.  
  1192. /*****************************************************************************
  1193. *
  1194. *   AttachInstance (viewer, picture, pntX, pntY, align,
  1195. *                   scaleX, scaleY, draw, data, cleanup)
  1196. *       Connects a picture to a viewer, with extra instance data
  1197. *
  1198. *****************************************************************************/
  1199.  
  1200. void AttachInstance (VieweR viewer, SegmenT picture, Int4 pntX, Int4 pntY,
  1201.                      Int2 align, Int4 scaleX, Int4 scaleY, VwrDrawProc draw,
  1202.                      VoidPtr data, VwrFreeProc cleanup)
  1203.  
  1204. {
  1205.   AttachCommon (viewer, picture, pntX, pntY, align,
  1206.                 scaleX, scaleY, draw, data, cleanup);
  1207. }
  1208.  
  1209. /*****************************************************************************
  1210. *
  1211. *   SetViewerProcs (viewer, click, drag, release, pan)
  1212. *       Attaches program responsiveness callbacks to a viewer
  1213. *
  1214. *****************************************************************************/
  1215.  
  1216. void SetViewerProcs (VieweR viewer, VwrClckProc click, VwrClckProc drag,
  1217.                      VwrClckProc release, VwrPanProc pan)
  1218.  
  1219. {
  1220.   ViewPData  extra;
  1221.  
  1222.   if (viewer != NULL) {
  1223.     GetPanelExtra ((PaneL) viewer, &extra);
  1224.     extra.click = click;
  1225.     extra.drag = drag;
  1226.     extra.release = release;
  1227.     extra.pan = pan;
  1228.     SetPanelExtra ((PaneL) viewer, &extra);
  1229.   }
  1230. }
  1231.  
  1232. /*****************************************************************************
  1233. *
  1234. *   SetViewerData (viewer, data, cleanup)
  1235. *       Attaches instance data to a viewer
  1236. *
  1237. *****************************************************************************/
  1238.  
  1239. void SetViewerData (VieweR viewer, VoidPtr data, VwrFreeProc cleanup)
  1240.  
  1241. {
  1242.   ViewPData  extra;
  1243.  
  1244.   if (viewer != NULL) {
  1245.     GetPanelExtra ((PaneL) viewer, &extra);
  1246.     extra.data = data;
  1247.     extra.cleanup = cleanup;
  1248.     SetPanelExtra ((PaneL) viewer, &extra);
  1249.   }
  1250. }
  1251.  
  1252. /*****************************************************************************
  1253. *
  1254. *   GetViewerData (viewer)
  1255. *       Returns the instance data attached to a viewer
  1256. *
  1257. *****************************************************************************/
  1258.  
  1259. VoidPtr GetViewerData (VieweR viewer)
  1260.  
  1261. {
  1262.   ViewPData  extra;
  1263.  
  1264.   if (viewer != NULL) {
  1265.     GetPanelExtra ((PaneL) viewer, &extra);
  1266.     return (extra.data);
  1267.   } else {
  1268.     return NULL;
  1269.   }
  1270. }
  1271.  
  1272. /*****************************************************************************
  1273. *
  1274. *   ViewerBox (viewer, world, port, view, scaleX, scaleY)
  1275. *       Returns the world and port boxes, view rect, and scales of a viewer
  1276. *
  1277. *****************************************************************************/
  1278.  
  1279. void ViewerBox (VieweR viewer, BoxPtr world, BoxPtr port,
  1280.                 RectPtr view, Int4Ptr scaleX, Int4Ptr scaleY)
  1281.  
  1282. {
  1283.   ViewPData  extra;
  1284.  
  1285.   if (viewer != NULL) {
  1286.     GetPanelExtra ((PaneL) viewer, &extra);
  1287.     if (world != NULL) {
  1288.       *world = extra.scale.world;
  1289.     }
  1290.     if (port != NULL) {
  1291.       *port = extra.scale.port;
  1292.     }
  1293.     if (view != NULL) {
  1294.       *view = extra.scale.view;
  1295.     }
  1296.     if (scaleX != NULL) {
  1297.       *scaleX = extra.scale.scaleX;
  1298.     }
  1299.     if (scaleY != NULL) {
  1300.       *scaleY = extra.scale.scaleY;
  1301.     }
  1302.   }
  1303. }
  1304.  
  1305. /*****************************************************************************
  1306. *
  1307. *   SearchSegment (segment, pt, pnt, scale, prID, prCt)
  1308. *       Returns the deepest segment that contains the pnt in world coordinates
  1309. *
  1310. *****************************************************************************/
  1311.  
  1312. static SegmenT SearchSegment (SegmenT segment, PoinT pt, PntPtr pnt,
  1313.                               ScaleInfo *scale, Uint2Ptr prID, Uint2Ptr prCt)
  1314.  
  1315. {
  1316.   double   aspect;
  1317.   BtmPPtr  btm;
  1318.   double   cosTheta;
  1319.   Uint2    count;
  1320.   CstPPtr  cst;
  1321.   Int2     dist;
  1322.   SegmenT  foundPrim;
  1323.   SegmenT  foundSeg;
  1324.   double   head;
  1325.   BasePPtr item;
  1326.   LblPPtr  lbl;
  1327.   LinPPtr  lin;
  1328.   MrkPPtr  mrk;
  1329.   PoinT    pt1;
  1330.   PoinT    pt2;
  1331.   PoinT    pts [4];
  1332.   RecT     r;
  1333.   RecPPtr  rec;
  1334.   SegPPtr  seg;
  1335.   double   sinTheta;
  1336.   SymPPtr  sym;
  1337.   PoinT    vpt;
  1338.   double   theta;
  1339.   double   x0, x1, x2;
  1340.   double   y0, y1, y2;
  1341.  
  1342.   foundSeg = NULL;
  1343.   foundPrim = NULL;
  1344.   if (segment != NULL && pnt != NULL && scale != NULL && prID != NULL && prCt != NULL) {
  1345.     seg = (SegPPtr) segment;
  1346.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  1347.       if (PntInBox (&(seg->seg.box), pnt, &(seg->seg.margin), scale)) {
  1348.         item = seg->seg.head;
  1349.         count = 1;
  1350.         while (item != NULL && foundSeg == NULL && foundPrim == NULL) {
  1351.           switch (item->code) {
  1352.             case PICTURE :
  1353.               Message (MSG_ERROR, "FindSegment child is a picture");
  1354.               break;
  1355.             case SEGMENT :
  1356.               foundSeg = SearchSegment ((SegmenT) item, pt, pnt, scale, prID, prCt);
  1357.               break;
  1358.             case ATTRIBUTE :
  1359.               break;
  1360.             case RECTANGLE :
  1361.               rec = (RecPPtr) item;
  1362.               if (BoxInViewport (&r, &(rec->box), &(rec->rct), scale)) {
  1363.                 InsetRect (&r, -RECT_PROXIMITY, -RECT_PROXIMITY);
  1364.                 if (PtInRect (pt, &r)) {
  1365.                   foundPrim = (SegmenT) seg;
  1366.                   *prID = rec->primID;
  1367.                   *prCt = count;
  1368.                 }
  1369.               }
  1370.               break;
  1371.             case LINE :
  1372.               lin = (LinPPtr) item;
  1373.               if (LineInViewport (&pt1, &pt2, &(lin->pnt1), &(lin->pnt2), &(lin->rct), scale)) {
  1374.                 if (pt1.x != pt2.x || pt1.y != pt2.y) {
  1375.                   if (pt.x + ARROW_LENGTH > MIN (pt1.x, pt2.x) - LINE_PROXIMITY &&
  1376.                       pt.x - ARROW_LENGTH < MAX (pt1.x, pt2.x) + LINE_PROXIMITY &&
  1377.                       pt.y + ARROW_LENGTH > MIN (pt1.y, pt2.y) - LINE_PROXIMITY &&
  1378.                       pt.y - ARROW_LENGTH < MAX (pt1.y, pt2.y) + LINE_PROXIMITY) {
  1379.                     x0 = (double) pt.x;
  1380.                     y0 = (double) pt.y;
  1381.                     x1 = (double) pt1.x;
  1382.                     y1 = (double) pt1.y;
  1383.                     x2 = (double) pt2.x;
  1384.                     y2 = (double) pt2.y;
  1385.                     dist = (Int2) (ABS (x0 * (y1 - y2) + y0 * (x2 - x1) + x1 * y2 - x2 * y1) /
  1386.                                    sqrt ((y1 - y2) * (y1 - y2) + (x1 - x2) * (x1 - x2)));
  1387.                     if (dist < LINE_PROXIMITY) {
  1388.                       foundPrim = (SegmenT) seg;
  1389.                       *prID = lin->primID;
  1390.                     } else if (lin->arrow) {
  1391.                       head = (double) ARROW_LENGTH;
  1392.                       if (pt1.x != pt2.x) {
  1393.                         theta = atan2 ((double) (pt2.y - pt1.y), (double) (pt2.x - pt1.x));
  1394.                         cosTheta = cos (theta);
  1395.                         sinTheta = sin (theta);
  1396.                       } else if (pt2.y > pt1.y) {
  1397.                         cosTheta = 0.0;
  1398.                         sinTheta = 1.0;
  1399.                       } else {
  1400.                         cosTheta = 0.0;
  1401.                         sinTheta = -1.0;
  1402.                       }
  1403.                       pts [0].x = pt2.x;
  1404.                       pts [0].y = pt2.y;
  1405.                       aspect = (double) ARROW_ASPECT;
  1406.                       pts [1].x = pt2.x - (Int2) (head * (sinTheta + aspect * cosTheta));
  1407.                       pts [1].y = pt2.y + (Int2) (head * (cosTheta - aspect * sinTheta));
  1408.                       pts [2].x = pt2.x + (Int2) (head * (sinTheta - aspect * cosTheta));
  1409.                       pts [2].y = pt2.y - (Int2) (head * (cosTheta + aspect * sinTheta));
  1410.                       pts [0].x = (pts [1].x + pts [2].x) / 2;
  1411.                       pts [0].y = (pts [1].y + pts [2].y) / 2;
  1412.                       x0 = (double) pt.x;
  1413.                       y0 = (double) pt.y;
  1414.                       x2 = (double) ((pt2.x + (pts [1].x + pts [2].x) / 2) / 2);
  1415.                       y2 = (double) ((pt2.y + (pts [1].y + pts [2].y) / 2) / 2);
  1416.                       dist = (Int2) (sqrt ((x2 - x0) * (x2 - x0) + (y2 - y0) * (y2 - y0)));
  1417.                       if (dist < ARROW_LENGTH) {
  1418.                         foundPrim = (SegmenT) seg;
  1419.                         *prID = lin->primID;
  1420.                         *prCt = count;
  1421.                       }
  1422.                     }
  1423.                   }
  1424.                 }
  1425.               }
  1426.               break;
  1427.             case SYMBOL :
  1428.               sym = (SymPPtr) item;
  1429.               if (PntInViewport (&vpt, &(sym->pnt), &(sym->rct), scale)) {
  1430.                 r = sym->rct;
  1431.                 InsetRect (&r, -GENERAL_PROXIMITY, -GENERAL_PROXIMITY);
  1432.                 OffsetRect (&r, vpt.x, vpt.y);
  1433.                 if (PtInRect (pt, &r)) {
  1434.                   foundPrim = (SegmenT) seg;
  1435.                   *prID = sym->primID;
  1436.                   *prCt = count;
  1437.                 }
  1438.               }
  1439.               break;
  1440.             case BITMAP :
  1441.               btm = (BtmPPtr) item;
  1442.               if (PntInViewport (&vpt, &(btm->pnt), &(btm->rct), scale)) {
  1443.                 r = btm->rct;
  1444.                 InsetRect (&r, -GENERAL_PROXIMITY, -GENERAL_PROXIMITY);
  1445.                 OffsetRect (&r, vpt.x, vpt.y);
  1446.                 if (PtInRect (pt, &r)) {
  1447.                   foundPrim = (SegmenT) seg;
  1448.                   *prID = btm->primID;
  1449.                   *prCt = count;
  1450.                 }
  1451.               }
  1452.               break;
  1453.             case CUSTOM :
  1454.               cst = (CstPPtr) item;
  1455.               if (PntInViewport (&vpt, &(cst->pnt), &(cst->rct), scale)) {
  1456.                 r = cst->rct;
  1457.                 InsetRect (&r, -GENERAL_PROXIMITY, -GENERAL_PROXIMITY);
  1458.                 OffsetRect (&r, vpt.x, vpt.y);
  1459.                 if (PtInRect (pt, &r)) {
  1460.                   foundPrim = (SegmenT) seg;
  1461.                   *prID = cst->primID;
  1462.                   *prCt = count;
  1463.                 }
  1464.               }
  1465.               break;
  1466.             case MARKER :
  1467.               mrk = (MrkPPtr) item;
  1468.               if (PntInViewport (&vpt, &(mrk->pnt), &(mrk->rct), scale)) {
  1469.                 r = mrk->rct;
  1470.                 InsetRect (&r, -GENERAL_PROXIMITY, -GENERAL_PROXIMITY);
  1471.                 OffsetRect (&r, vpt.x, vpt.y);
  1472.                 if (PtInRect (pt, &r)) {
  1473.                   foundPrim = (SegmenT) seg;
  1474.                   *prID = mrk->primID;
  1475.                   *prCt = count;
  1476.                 }
  1477.               }
  1478.               break;
  1479.             case LABEL :
  1480.               lbl = (LblPPtr) item;
  1481.               if (PntInViewport (&vpt, &(lbl->pnt), &(lbl->rct), scale)) {
  1482.                 r = lbl->rct;
  1483.                 InsetRect (&r, -GENERAL_PROXIMITY, -GENERAL_PROXIMITY);
  1484.                 OffsetRect (&r, vpt.x, vpt.y);
  1485.                 if (PtInRect (pt, &r)) {
  1486.                   foundPrim = (SegmenT) seg;
  1487.                   *prID = lbl->primID;
  1488.                   *prCt = count;
  1489.                 }
  1490.               }
  1491.               break;
  1492.             default :
  1493.               break;
  1494.           }
  1495.           item = item->next;
  1496.           count++;
  1497.         }
  1498.         while (item != NULL && foundSeg == NULL) {
  1499.           switch (item->code) {
  1500.             case PICTURE :
  1501.               Message (MSG_ERROR, "FindSegment child is a picture");
  1502.               break;
  1503.             case SEGMENT :
  1504.               foundSeg = SearchSegment ((SegmenT) item, pt, pnt, scale, prID, prCt);
  1505.               break;
  1506.             default :
  1507.               break;
  1508.           }
  1509.           item = item->next;
  1510.         }
  1511.         if (foundSeg == NULL) {
  1512.           foundSeg = foundPrim;
  1513.         }
  1514.       }
  1515.     } else {
  1516.       Message (MSG_ERROR, "SearchSegment argument not a segment or picture");
  1517.     }
  1518.   }
  1519.   return foundSeg;
  1520. }
  1521.  
  1522. /*****************************************************************************
  1523. *
  1524. *   FindSegment (viewer, pt, segID, primID, primCt)
  1525. *       Returns the deepest segment that contains the pt
  1526. *
  1527. *****************************************************************************/
  1528.  
  1529. SegmenT FindSegment (VieweR viewer, PoinT pt, Uint2Ptr segID, Uint2Ptr primID, Uint2Ptr primCt)
  1530.  
  1531. {
  1532.   ViewPData  extra;
  1533.   SegmenT    found;
  1534.   PicPPtr    pic;
  1535.   PntInfo    pnt;
  1536.   Uint2      prCt;
  1537.   Uint2      prID;
  1538.   Uint2      sgID;
  1539.  
  1540.   found = NULL;
  1541.   prCt = 0;
  1542.   prID = 0;
  1543.   sgID = 0;
  1544.   if (viewer != NULL) {
  1545.     GetPanelExtra ((PaneL) viewer, &extra);
  1546.     pic = (PicPPtr) extra.picture;
  1547.     if (pic->base.code == PICTURE) {
  1548.       MapViewerToWorld (viewer, pt, &pnt);
  1549.       found = SearchSegment ((SegmenT) pic, pt, &pnt, &(extra.scale), &prID, &prCt);
  1550.     } else {
  1551.       Message (MSG_ERROR, "FindSegment argument not a picture");
  1552.     }
  1553.   }
  1554.   if (found != NULL) {
  1555.     sgID = SegmentID (found);
  1556.   }
  1557.   if (segID != NULL) {
  1558.     *segID = sgID;
  1559.   }
  1560.   if (primID != NULL) {
  1561.     *primID = prID;
  1562.   }
  1563.   if (primCt != NULL) {
  1564.     *primCt = prCt;
  1565.   }
  1566.   return found;
  1567. }
  1568.  
  1569. /*****************************************************************************
  1570. *
  1571. *   ShowSegment (viewer, segment)
  1572. *       Makes a segment visible
  1573. *
  1574. *****************************************************************************/
  1575.  
  1576. void ShowSegment (VieweR viewer, SegmenT segment)
  1577.  
  1578. {
  1579.   RecT       d;
  1580.   ViewPData  extra;
  1581.   RecT       r;
  1582.   RecT       s;
  1583.   SegPPtr    seg;
  1584.   WindoW     tempPort;
  1585.  
  1586.   if (viewer != NULL && segment != NULL) {
  1587.     seg = (SegPPtr) segment;
  1588.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  1589.       if (! seg->seg.visible) {
  1590.         seg->seg.visible = TRUE;
  1591.         GetPanelExtra ((PaneL) viewer, &extra);
  1592.         if (BoxInViewport (&r, &(seg->seg.box), &(seg->seg.margin), &(extra.scale))) {
  1593.           r.left -= 1 - seg->seg.margin.left;
  1594.           r.top -= 1 - seg->seg.margin.top;
  1595.           r.right += 1 + seg->seg.margin.right;
  1596.           r.bottom += 1 + seg->seg.margin.bottom;
  1597.           if (Visible (viewer) && AllParentsVisible (viewer)) {
  1598.             ObjectRect (viewer, &s);
  1599.             InsetRect (&s, 2, 2);
  1600.             SectRect (&r, &s, &d);
  1601.             tempPort = SavePort (viewer);
  1602.             Select (viewer);
  1603.             InvalRect (&d);
  1604.             RestorePort (tempPort);
  1605.           }
  1606.         }
  1607.       }
  1608.     } else {
  1609.       Message (MSG_ERROR, "ShowSegment argument not a segment or picture");
  1610.     }
  1611.   }
  1612. }
  1613.  
  1614. /*****************************************************************************
  1615. *
  1616. *   HideSegment (viewer, segment)
  1617. *       Maps a segment invisible
  1618. *
  1619. *****************************************************************************/
  1620.  
  1621. void HideSegment (VieweR viewer, SegmenT segment)
  1622.  
  1623. {
  1624.   RecT       d;
  1625.   ViewPData  extra;
  1626.   RecT       r;
  1627.   RecT       s;
  1628.   SegPPtr    seg;
  1629.   WindoW     tempPort;
  1630.  
  1631.   if (viewer != NULL && segment != NULL) {
  1632.     seg = (SegPPtr) segment;
  1633.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  1634.       if (seg->seg.visible) {
  1635.         seg->seg.visible = FALSE;
  1636.         GetPanelExtra ((PaneL) viewer, &extra);
  1637.         if (BoxInViewport (&r, &(seg->seg.box), &(seg->seg.margin), &(extra.scale))) {
  1638.           r.left -= 1 - seg->seg.margin.left;
  1639.           r.top -= 1 - seg->seg.margin.top;
  1640.           r.right += 1 + seg->seg.margin.right;
  1641.           r.bottom += 1 + seg->seg.margin.bottom;
  1642.           if (Visible (viewer) && AllParentsVisible (viewer)) {
  1643.             ObjectRect (viewer, &s);
  1644.             InsetRect (&s, 2, 2);
  1645.             SectRect (&r, &s, &d);
  1646.             tempPort = SavePort (viewer);
  1647.             Select (viewer);
  1648.             InvalRect (&d);
  1649.             RestorePort (tempPort);
  1650.           }
  1651.         }
  1652.       }
  1653.     } else {
  1654.       Message (MSG_ERROR, "ShowSegment argument not a segment or picture");
  1655.     }
  1656.   }
  1657. }
  1658.  
  1659. /*****************************************************************************
  1660. *
  1661. *   HighlightSegment (viewer, segment, highlight)
  1662. *       Highlights a segment
  1663. *
  1664. *****************************************************************************/
  1665.  
  1666. void HighlightSegment (VieweR viewer, SegmenT segment, Int1 highlight)
  1667.  
  1668. {
  1669.   RecT       d;
  1670.   ViewPData  extra;
  1671.   RecT       r;
  1672.   RecT       s;
  1673.   SegPPtr    seg;
  1674.   WindoW     tempPort;
  1675.  
  1676.   if (viewer != NULL && segment != NULL) {
  1677.     seg = (SegPPtr) segment;
  1678.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  1679.       if (seg->seg.highlight != highlight) {
  1680.         seg->seg.highlight = highlight;
  1681.         if (seg->seg.visible) {
  1682.           if (Visible (viewer) && AllParentsVisible (viewer)) {
  1683.             GetPanelExtra ((PaneL) viewer, &extra);
  1684.             if (BoxInViewport (&r, &(seg->seg.box), &(seg->seg.margin), &(extra.scale))) {
  1685.               r.left -= 1 - seg->seg.margin.left;
  1686.               r.top -= 1 - seg->seg.margin.top;
  1687.               r.right += 1 + seg->seg.margin.right;
  1688.               r.bottom += 1 + seg->seg.margin.bottom;
  1689.               InsetRect (&r, -1, -1);
  1690.               ObjectRect (viewer, &s);
  1691.               InsetRect (&s, 2, 2);
  1692.               SectRect (&r, &s, &d);
  1693.               tempPort = SavePort (viewer);
  1694.               Select (viewer);
  1695.               InvalRect (&d);
  1696.               RestorePort (tempPort);
  1697.             }
  1698.           }
  1699.         }
  1700.       }
  1701.     } else {
  1702.       Message (MSG_ERROR, "HighlightSegment argument not a segment or picture");
  1703.     }
  1704.   }
  1705. }
  1706.  
  1707. /*****************************************************************************
  1708. *
  1709. *   HighlightPrimitive (viewer, segment, primitive, highlight)
  1710. *       Highlights a primitive
  1711. *
  1712. *****************************************************************************/
  1713.  
  1714. void HighlightPrimitive (VieweR viewer, SegmenT segment, PrimitivE primitive, Int1 highlight)
  1715.  
  1716. {
  1717.   RecT       d;
  1718.   ViewPData  extra;
  1719.   BasePPtr   item;
  1720.   LinPPtr    lin;
  1721.   RecT       r;
  1722.   RecPPtr    rec;
  1723.   RecT       s;
  1724.   SegPPtr    seg;
  1725.   WindoW     tempPort;
  1726.  
  1727.   if (viewer != NULL && segment != NULL) {
  1728.     seg = (SegPPtr) segment;
  1729.     if (seg->base.code == SEGMENT || seg->base.code == PICTURE) {
  1730.       item = (BasePPtr) primitive;
  1731.       if (item != NULL && (item->code == RECTANGLE || item->code == LINE)) {
  1732.         if (item->code == RECTANGLE) {
  1733.           rec = (RecPPtr) item;
  1734.           rec->highlight = highlight;
  1735.         } else if (item->code == LINE) {
  1736.           lin = (LinPPtr) item;
  1737.           lin->highlight = highlight;
  1738.         }
  1739.         if (seg->seg.visible) {
  1740.           if (Visible (viewer) && AllParentsVisible (viewer)) {
  1741.             GetPanelExtra ((PaneL) viewer, &extra);
  1742.             if (BoxInViewport (&r, &(seg->seg.box), &(seg->seg.margin), &(extra.scale))) {
  1743.               r.left -= 1 - seg->seg.margin.left;
  1744.               r.top -= 1 - seg->seg.margin.top;
  1745.               r.right += 1 + seg->seg.margin.right;
  1746.               r.bottom += 1 + seg->seg.margin.bottom;
  1747.               InsetRect (&r, -1, -1);
  1748.               ObjectRect (viewer, &s);
  1749.               InsetRect (&s, 2, 2);
  1750.               SectRect (&r, &s, &d);
  1751.               tempPort = SavePort (viewer);
  1752.               Select (viewer);
  1753.               InvalRect (&d);
  1754.               RestorePort (tempPort);
  1755.             }
  1756.           }
  1757.         }
  1758.       }
  1759.     } else {
  1760.       Message (MSG_ERROR, "HighlightPrimitive argument not a segment or picture");
  1761.     }
  1762.   }
  1763. }
  1764.  
  1765. /*****************************************************************************
  1766. *
  1767. *   PrintViewer (viewer)
  1768. *       Prints the picture.
  1769. *
  1770. *****************************************************************************/
  1771.  
  1772. void PrintViewer (VieweR viewer)
  1773.  
  1774. {
  1775.   AttPData   attributes;
  1776.   AttPData   current;
  1777.   ViewPData  extra;
  1778.   Boolean    goOn;
  1779.   PicPPtr    pic;
  1780.   WindoW     w;
  1781.  
  1782.   if (viewer != NULL) {
  1783.     GetPanelExtra ((PaneL) viewer, &extra);
  1784.     pic = (PicPPtr) extra.picture;
  1785.     if (pic != NULL) {
  1786.       if (pic->base.code == PICTURE) {
  1787.         w = StartPrinting ();
  1788.         if (w != NULL) {
  1789.           goOn = StartPage ();
  1790.           if (goOn) {
  1791.             PrintingRect (&(extra.scale.view));
  1792.             attributes.flags = NO_ATTS;
  1793.             attributes.color [0] = BLACK_COLOR [0];
  1794.             attributes.color [1] = BLACK_COLOR [1];
  1795.             attributes.color [2] = BLACK_COLOR [2];
  1796.             attributes.linestyle = SOLID_LINE;
  1797.             attributes.shading = SOLID_SHADING;
  1798.             attributes.penwidth = STD_PEN_WIDTH;
  1799.             attributes.mode = COPY_MODE;
  1800.             attributes.highlight = PLAIN_SEGMENT;
  1801.             current = *(&attributes);
  1802.             extra.scale.force = TRUE;
  1803.             DrawSegment ((SegPPtr) pic, &attributes, ¤t, &(extra.scale));
  1804.             SetAttributes (&attributes, ¤t);
  1805.             goOn = EndPage ();
  1806.           }
  1807.           EndPrinting (w);
  1808.         }
  1809.       } else {
  1810.         Message (MSG_ERROR, "PrintViewer target is not a picture");
  1811.       }
  1812.     }
  1813.   }
  1814. }
  1815.  
  1816. /*****************************************************************************
  1817. *
  1818. *   MapWorldToViewer (viewer, pnt, pt)
  1819. *       Maps a pnt in world coordinates to a point in viewer coordinates
  1820. *
  1821. *****************************************************************************/
  1822.  
  1823. void MapWorldToViewer (VieweR viewer, PntInfo pnt, PointPtr pt)
  1824.  
  1825. {
  1826.   ViewPData  extra;
  1827.  
  1828.   if (viewer != NULL && pt != NULL) {
  1829.     GetPanelExtra ((PaneL) viewer, &extra);
  1830.     MapWorldPointToPixel (pt, &pnt, &(extra.scale));
  1831.   }
  1832. }
  1833.  
  1834. /*****************************************************************************
  1835. *
  1836. *   MapViewerToWorld (viewer, pt, pnt)
  1837. *       Maps a point in viewer coordinates to a pnt in world coordinates
  1838. *
  1839. *****************************************************************************/
  1840.  
  1841. void MapViewerToWorld (VieweR viewer, PoinT pt, PntPtr pnt)
  1842.  
  1843. {
  1844.   ViewPData  extra;
  1845.  
  1846.   if (viewer != NULL && pnt != NULL) {
  1847.     GetPanelExtra ((PaneL) viewer, &extra);
  1848.     MapPixelPointToWorld (pnt, &pt, &(extra.scale));
  1849.   }
  1850. }
  1851.